package run.halo.app.repository;

import java.util.Collection;
import java.util.List;
import java.util.Set;
import org.springframework.data.jpa.repository.Query;
import org.springframework.lang.NonNull;
import run.halo.app.model.entity.SiteTag;
import run.halo.app.model.enums.SiteStatus;
import run.halo.app.model.projection.TagSiteSiteCountProjection;
import run.halo.app.repository.base.BaseRepository;


/**
 * Site tag repository.
 *
 * @author johnniang
 * @author ryanwang
 * @date 2019-03-19
 */
public interface SiteTagRepository extends BaseRepository<SiteTag, Integer> {

    /**
     * Finds all site tags by site id.
     *
     * @param siteId site id must not be null
     * @return a list of site tags
     */
    @NonNull
    List<SiteTag> findAllBySiteId(@NonNull Integer siteId);

    /**
     * Finds all tag ids by site id.
     *
     * @param siteId site id must not be null
     * @return a set of tag id
     */
    @Query("select siteTag.tagId from SiteTag siteTag where siteTag.siteId = ?1")
    @NonNull
    Set<Integer> findAllTagIdsBySiteId(@NonNull Integer siteId);

    /**
     * Finds all site tags by tag id.
     *
     * @param tagId tag id must not be null
     * @return a list of site tags
     */
    @NonNull
    List<SiteTag> findAllByTagId(@NonNull Integer tagId);

    /**
     * Finds all site id by tag id.
     *
     * @param tagId tag id must not be null
     * @return a set of site id
     */
    @Query("select siteTag.siteId from SiteTag siteTag where siteTag.tagId = ?1")
    @NonNull
    Set<Integer> findAllSiteIdsByTagId(@NonNull Integer tagId);

    /**
     * Finds all site id by tag id and site status.
     *
     * @param tagId tag id must not be null
     * @param status site status
     * @return a set of site id
     */
    @Query("select siteTag.siteId from SiteTag siteTag,Site site where siteTag.tagId = ?1 and "
        + "site.id = siteTag.siteId and site.status = ?2")
    @NonNull
    Set<Integer> findAllSiteIdsByTagId(@NonNull Integer tagId, @NonNull SiteStatus status);

    /**
     * Finds all tags by site id in.
     *
     * @param siteIds site id collection
     * @return a list of site tags
     */
    @NonNull
    List<SiteTag> findAllBySiteIdIn(@NonNull Collection<Integer> siteIds);

    /**
     * Deletes site tags by site id.
     *
     * @param siteId site id must not be null
     * @return a list of site tag deleted
     */
    @NonNull
    List<SiteTag> deleteBySiteId(@NonNull Integer siteId);

    /**
     * Deletes site tags by tag id.
     *
     * @param tagId tag id must not be null
     * @return a list of site tag deleted
     */
    @NonNull
    List<SiteTag> deleteByTagId(@NonNull Integer tagId);

    /**
     * Finds site count by tag id collection.
     *
     * @param tagIds tag id collection must not be null
     * @return a list of tag site count projection
     */
    @Query("select new run.halo.app.model.projection.TagSiteSiteCountProjection(count(st.siteId),"
        + " st.tagId) from SiteTag st where st.tagId in ?1 group by st.tagId")
    @NonNull
    List<TagSiteSiteCountProjection> findSiteCountByTagIds(@NonNull Collection<Integer> tagIds);

    /**
     * Finds site count of tag.
     *
     * @return a list of tag site count projection
     */
    @Query("select new run.halo.app.model.projection.TagSiteSiteCountProjection(count(pt.siteId),"
        + " pt.tagId) from SiteTag pt inner join Site p on p.id=pt.siteId and"
        + " p.status<>2 group by pt.tagId")
    @NonNull
    List<TagSiteSiteCountProjection> findSiteCount();
}
